/*
 * 异常过滤器
 */

import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
  Logger,
} from '@nestjs/common';
import { Request, Response } from 'express';

@Catch()
// 统一错误返回格式
export class ExceptionsFilter implements ExceptionFilter {
  // constructor(private readonly loggingService: LoggingService) {}
  private readonly logger = new Logger(ExceptionsFilter.name);

  catch(exception: unknown, host: ArgumentsHost) {
    // * exception 当前正在处理的异常对象
    // * host 是传递给原始处理程序的参数的一个包装(Response/Request)的引用

    // 获取请求上下文
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    const errorResponse = this.getErrorResponse(exception, request);
    const status = errorResponse.statusCode;

    this.logError(exception, request, status);
    response.status(status).json(errorResponse);
  }

  private getErrorResponse(
    exception: unknown,
    request: Request,
  ): ApiResponseData<null> {
    let status: number;
    let message: string = '内部服务器错误';
    let error: string | undefined;

    if (exception instanceof CustomExceptionFilter) {
      status = exception.getStatus();
      message = exception.message;
      error = exception.name;
    } else if (exception instanceof HttpException) {
      status = exception.getStatus();
      const response = exception.getResponse();
      switch (typeof response) {
        case 'string':
          message = response;
          break;
        default:
          message = (response as any).message || message;
          error = (response as any).error;
          break;
      }
    } else if (exception instanceof Error) {
      // 处理特定错误类型
      switch (error) {
        case 'PrismaClientKnownRequestError':
          status = HttpStatus.BAD_REQUEST;
          break;
        default:
          status = HttpStatus.INTERNAL_SERVER_ERROR;
          break;
      }
    }

    return {
      path: request.url,
      statusCode: status,
      message,
      error,
    };
  }

  private logError(exception: unknown, request: Request, status: number) {
    let errorMessage = '';

    if (exception instanceof HttpException) {
      errorMessage = `${exception.getStatus()} - ${exception.message}`;
    } else if (exception instanceof Error) {
      errorMessage = `${exception.name} - ${exception.message}`;
    } else {
      errorMessage = `Unknown error: ${JSON.stringify(exception)}`;
    }

    this.logger.error(
      `Error occurred: ${errorMessage}`,
      // exception instanceof Error ? exception.stack : undefined,
    );
    // this.logger.error(JSON.stringify(exception, null, 2));

    if (status >= 500) {
      this.logger.error(
        `Request details: ${JSON.stringify({
          method: request.method,
          url: request.url,
          body: request.body,
          query: request.query,
          params: request.params,
        })}`,
      );
    }
  }
}

export class CustomExceptionFilter extends HttpException {
  constructor(message: string, status: HttpStatus) {
    super({ message, status }, status);
  }
}
